package org.nutboat.core;

import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.DoubleBuffer;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.nio.LongBuffer;
import java.nio.ShortBuffer;
import java.util.BitSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class GameData {
	private class DataListenerList extends ListenerList<DataListener, DataEvent> {
	
		@Override
		protected void handleEvent(DataListener listener, DataEvent event) {
			listener.onDataChanged(event);
		}
	}

	private DataListenerList listenerList;
	
	private HashMap<String, Object> dataMap;

	public GameData(int capacity, float factor) {
		dataMap = new HashMap<String, Object>(capacity, factor);
		listenerList = new DataListenerList();
	}
	
	public GameData(int capacity) {
		dataMap = new HashMap<String, Object>(capacity);
		listenerList = new DataListenerList();
	}
	
	public GameData() {
		dataMap = new HashMap<String, Object>();
		listenerList = new DataListenerList();
	}
	
	public DataListener[] getDataListeners() {
		DataListener[] listeners = new DataListener[listenerList.size()];
		for (int i = 0; i < listeners.length; i++) {
			listeners[i] = listenerList.getListener(i);
		}
		return listeners;
	}
	
	public void addDataListener(DataListener l) {
		listenerList.addListener(l);
	}
	
	public boolean removeDataListener(DataListener l) {
		return listenerList.removeListener(l);
	}
	
	public void putAll(GameData data) {
		if (data != null) {			
			dataMap.putAll(data.dataMap);
		}
	}
	
	public void put(String name, Object value) {
		Object oldValue = dataMap.put(name, value);
		if (oldValue != null && listenerList.isNotEmpty()) {
			listenerList.catchEvent(new DataEvent(this, name, oldValue, value));
		}
	}

	public void putBoolean(String name, boolean value) {
		put(name, value ? Boolean.TRUE : Boolean.FALSE);
	}	

	public void putBooleanArray(String name, boolean[] value) {
		put(name, value);
	}
	
	public void putBooleanDyadicArray(String name, boolean[][] value) {
		put(name, value);
	}
	
	public void putByte(String name, byte value) {
		put(name, Byte.valueOf(value));
	}
	
	public void putByteArray(String name, byte[] value) {
		put(name, value);
	}
	
	public void putByteDyadicArray(String name, byte[][] value) {
		put(name, value);
	}
	
	public void putCharacter(String name, char value) {
		put(name, Character.valueOf(value));
	}
	
	public void putCharacterArray(String name, char[] value) {
		put(name, value);
	}
	
	public void putCharacterDyadicArray(String name, char[][] value) {
		put(name, value);
	}
	
	public void putShort(String name, short value) {
		put(name, Short.valueOf(value));
	}
	
	public void putShortArray(String name, short[] value) {
		put(name, value);
	}
	
	public void putShortDyadicArray(String name, short[][] value) {
		put(name, value);
	}
	
	public void putInteger(String name, int value) {
		put(name, Integer.valueOf(value));
	}
	
	public void putIntegerArray(String name, int[] value) {
		put(name, value);
	}
	
	public void putIntegerDyadicArray(String name, int[][] value) {
		put(name, value);
	}
	
	public void putLong(String name, long value) {
		put(name, Long.valueOf(value));
	}
	
	public void putLongArray(String name, long[] value) {
		put(name, value);
	}
	
	public void putLongDyadicArray(String name, long[][] value) {
		put(name, value);
	}
	
	public void putFloat(String name, float value) {
		put(name, Float.valueOf(value));
	}
	
	public void putFloatArray(String name, float[] value) {
		put(name, value);
	}
	
	public void putFloatDyadicArray(String name, float[][] value) {
		put(name, value);
	}
	
	public void putDouble(String name, double value) {
		put(name, Double.valueOf(value));
	}
	
	public void putDoubleArray(String name, double[] value) {
		put(name, value);
	}
	
	public void putDoubleDyadicArray(String name, double[][] value) {
		put(name, value);
	}
	
	public void putString(String name, String value) {
		put(name, value);
	}
	
	public void putStringArray(String name, String[] value) {
		put(name, value);
	}
	
	public void putStringDyadicArray(String name, String[][] value) {
		put(name, value);
	}
	
	public void putList(String name, List<?> value) {
		put(name, value);
	}
	
	public void putListArray(String name, List<?>[] value) {
		put(name, value);
	}

	public void putListDyadicArray(String name, List<?>[][] value) {
		put(name, value);
	}
	
	public void putMap(String name, Map<?, ?> value) {
		put(name, value);
	}
	
	public void putMapArray(String name, Map<?, ?>[] value) {
		put(name, value);
	}
	
	public void putMapDyadicArray(String name, Map<?, ?>[][] value) {
		put(name, value);
	}

	public void putBitSet(String name, BitSet value) {
		put(name, value);
	}

	public void putByteBuffer(String name, ByteBuffer value) {
		put(name, value);
	}

	public void putCharBuffer(String name, CharBuffer value) {
		put(name, value);
	}

	public void putShortBuff(String name, ShortBuffer value) {
		put(name, value);
	}

	public void putIntBuffer(String name, IntBuffer value) {
		put(name, value);
	}

	public void putLongBuffer(String name, LongBuffer value) {
		put(name, value);
	}

	public void putFloatBuffer(String name, FloatBuffer value) {
		put(name, value);
	}

	public void putDoubleBuffer(String name, DoubleBuffer value) {
		put(name, value);
	}
	
	@SuppressWarnings("unchecked")
	private <T> T get(String name, T defaultValue) {
		Object object = dataMap.get(name);
		if (object != null && object.getClass() == defaultValue.getClass()) {
			return (T) object;
		}
		return defaultValue;
	}

	@SuppressWarnings("unchecked")
	public <T> T get(String name, T defaultValue, Class<T> type) {
		Object object = dataMap.get(name);
		if (object != null && object.getClass() == type) {
			return (T) object;
		}
		return defaultValue;
	}
	
	public boolean getBoolean(String name, boolean defaultValue) {
		return get(name, defaultValue ? Boolean.TRUE : Boolean.FALSE).booleanValue();
	}
	
	public boolean[] getBooleanArray(String name, boolean[] defaultValue) {
		return get(name, defaultValue, boolean[].class);
	}
	
	public boolean[][] getBooleanDyadicArray(String name, boolean[][] defaultValue) {
		return get(name, defaultValue, boolean[][].class);
	}
	
	public byte getByte(String name, byte defaultValue) {
		return get(name, Byte.valueOf(defaultValue)).byteValue();
	}
	
	public byte[] getByteArray(String name, byte[] defaultValue) {
		return get(name, defaultValue, byte[].class);
	}
	
	public byte[][] getByteDyadicArray(String name, byte[][] defaultValue) {
		return get(name, defaultValue, byte[][].class);
	}
	
	public char getCharacter(String name, char defaultValue) {
		return get(name, Character.valueOf(defaultValue)).charValue();
	}
	
	public char[] getCharacterArray(String name, char[] defaultValue) {
		return get(name, defaultValue, char[].class);
	}
	
	public char[][] getCharacterDyadicArray(String name, char[][] defaultValue) {
		return get(name, defaultValue, char[][].class);
	}
	
	public short getShort(String name, short defaultValue) {
		return get(name, Short.valueOf(defaultValue)).shortValue();
	}
	
	public short[] getShortArray(String name, short[] defaultValue) {
		return get(name, defaultValue, short[].class);
	}
	
	public short[][] getShortDyadicArray(String name, short[][] defaultValue) {
		return get(name, defaultValue, short[][].class);
	}
	
	public int getInteger(String name, int defaultValue) {
		return get(name, Integer.valueOf(defaultValue)).intValue();
	}
	
	public int[] getIntegerArray(String name, int[] defaultValue) {
		return get(name, defaultValue, int[].class);
	}
	
	public int[][] getIntegerDyadicArray(String name, int[][] defaultValue) {
		return get(name, defaultValue, int[][].class);
	}
	
	public long getLong(String name, long defaultValue) {
		return get(name, Long.valueOf(defaultValue)).longValue();
	}
	
	public long[] getLongArray(String name, long[] defaultValue) {
		return get(name, defaultValue, long[].class);
	}
	
	public long[][] getLongDyadicArray(String name, long[][] defaultValue) {
		return get(name, defaultValue, long[][].class);
	}
	
	public float getFloat(String name, float defaultValue) {
		return get(name, Float.valueOf(defaultValue)).floatValue();
	}
	
	public float[] getFloatArray(String name, float[] defaultValue) {
		return get(name, defaultValue, float[].class);
	}
	
	public float[][] getFloatDyadicArray(String name, float[][] defaultValue) {
		return get(name, defaultValue, float[][].class);
	}
	
	public double getDouble(String name, double defaultValue) {
		return get(name, Double.valueOf(defaultValue)).doubleValue();
	}
	
	public double[] getDoubleArray(String name, double[] defaultValue) {
		return get(name, defaultValue, double[].class);
	}
	
	public double[][] getDoubleDyadicArray(String name, double[][] defaultValue) {
		return get(name, defaultValue, double[][].class);
	}
	
	public String getString(String name, String defaultValue) {
		return get(name, defaultValue, String.class);
	}
	
	public String[] getStringArray(String name, String[] defaultValue) {
		return get(name, defaultValue, String[].class);
	}
	
	public String[][] getStringDyadicArray(String name, String[][] defaultValue) {
		return get(name, defaultValue, String[][].class);
	}
	
	public List<?> getList(String name, List<?> defaultValue) {
		return get(name, defaultValue, List.class);
	}
	
	public List<?>[] getListArray(String name, List<?>[] defaultValue) {
		return get(name, defaultValue, List[].class);
	}

	public List<?>[][] getListDyadicArray(String name, List<?>[][] defaultValue) {
		return get(name, defaultValue, List[][].class);
	}
	
	public Map<?, ?> getMap(String name, Map<?, ?> defaultValue) {
		return get(name, defaultValue, Map.class);
	}
	
	public Map<?, ?>[] getMapArray(String name, Map<?, ?>[] defaultValue) {
		return get(name, defaultValue, Map[].class);
	}
	
	public Map<?, ?>[][] getMapDyadicArray(String name, Map<?, ?>[][] defaultValue) {
		return get(name, defaultValue, Map[][].class);
	}
	
	public BitSet getBitSet(String name, BitSet defaultValue) {
		return get(name, defaultValue, BitSet.class);
	}

	public ByteBuffer getByteBuffer(String name, ByteBuffer defaultValue) {
		return get(name, defaultValue, ByteBuffer.class);
	}

	public CharBuffer getCharBuffer(String name, CharBuffer defaultValue) {
		return get(name, defaultValue, CharBuffer.class);
	}

	public ShortBuffer getShortBuff(String name, ShortBuffer defaultValue) {
		return get(name, defaultValue, ShortBuffer.class);
	}

	public IntBuffer getIntBuffer(String name, IntBuffer defaultValue) {
		return get(name, defaultValue, IntBuffer.class);
	}

	public LongBuffer getLongBuffer(String name, LongBuffer defaultValue) {
		return get(name, defaultValue, LongBuffer.class);
	}

	public FloatBuffer getFloatBuffer(String name, FloatBuffer defaultValue) {
		return get(name, defaultValue, FloatBuffer.class);
	}

	public DoubleBuffer getDoubleBuffer(String name, DoubleBuffer defaultValue) {
		return get(name, defaultValue, DoubleBuffer.class);
	}
}